/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.bff.designtime.generator.entity.help;

import com.inspur.edp.bef.component.detailcmpentity.vm.VMComponent;
import com.inspur.edp.bef.component.detailcmpentity.vm.VMMethod;
import com.inspur.edp.bff.designtime.generator.VmGeneratorContext;
import com.inspur.edp.bff.designtime.generator.entity.VmEntityGenContext;
import com.inspur.edp.bff.spi.VMHelpConfig;
import com.inspur.edp.bff.spi.utils.ParameterInfo;
import com.inspur.edp.bff.spi.utils.ReflectInfo;
import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.property.ClassPropertyGenerator;
import com.inspur.edp.cef.spi.jsonser.base.StringUtils;
import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.formserver.viewmodel.action.MappedCdpAction;
import com.inspur.edp.formserver.viewmodel.action.ViewModelAction;
import com.inspur.edp.formserver.viewmodel.action.viewmodelbase.ViewModelParameter;
import com.inspur.edp.formserver.viewmodel.collection.ValueHelpConfigCollection;
import com.inspur.edp.formserver.viewmodel.common.ValueHelpConfig;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import lombok.var;
import org.eclipse.jdt.core.dom.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * HelpConfig属性的生成
 */
public class HelpMappingProGenerator extends ClassPropertyGenerator {

  private VmEntityGenContext entityGenContext;
  private VmGeneratorContext vmGenContext;

  public HelpMappingProGenerator(VmEntityGenContext entityGenContext,
                                 VmGeneratorContext vmGenContext) {
    this.entityGenContext = entityGenContext;
    this.vmGenContext = vmGenContext;
  }

  @Override
  protected ArrayList<Modifier.ModifierKeyword> getGetterAccessModifier() {
    ArrayList<Modifier.ModifierKeyword> list=new ArrayList<>();
    list.add(Modifier.ModifierKeyword.PUBLIC_KEYWORD);
    return list;
  }

  @Override
  protected ArrayList<Modifier.ModifierKeyword> getSetterAccessModifier() {
    ArrayList<Modifier.ModifierKeyword> list=new ArrayList<>();
    list.add(Modifier.ModifierKeyword.PUBLIC_KEYWORD);
    return list;
  }

  @Override
  protected String getPropertyName() {
    return "HelpConfig";
  }

  @Override
  protected TypeInfo getPropertyType() {
    TypeInfo typeInfo=new TypeInfo(HashMap.class);
    typeInfo.setIsParameterizedType(true);
    typeInfo.getArguments().add(new TypeInfo(String.class));
    typeInfo.getArguments().add(new TypeInfo(VMHelpConfig.class));
    addImport(HashMap.class.getTypeName());
    addImport(ParameterInfo.class.getTypeName());
    return typeInfo;
  }

  @Override
  protected String getFieldName() {
    return null;
  }

  @Override
  protected Block buildGetMethodBody() {
    Block block=ast.newBlock();
    addNewMapStatement(block);
    addPutItemsStatements(block);
    addReturnStatement(block);
    return block;
  }

  private void addNewMapStatement(Block block) {
    VariableDeclarationFragment variableDeclarationFragment=ast.newVariableDeclarationFragment();
    variableDeclarationFragment.setName(ast.newSimpleName("map"));

    ClassInstanceCreation classInstanceCreation=ast.newClassInstanceCreation();
    ParameterizedType parameterizedType1=ast.newParameterizedType(ast.newSimpleType(ast.newName(HashMap.class.getTypeName())));

    parameterizedType1.typeArguments().add(ast.newSimpleType(ast.newName(String.class.getTypeName())));
    parameterizedType1.typeArguments().add(new TypeInfo(VMHelpConfig.class).getType(ast, entityGenContext));
    classInstanceCreation.setType(parameterizedType1);
    variableDeclarationFragment.setInitializer(classInstanceCreation);

    VariableDeclarationStatement variableDeclarationStatement=ast.newVariableDeclarationStatement(variableDeclarationFragment);
    ParameterizedType parameterizedType=ast.newParameterizedType(ast.newSimpleType(ast.newName(HashMap.class.getTypeName())));

    parameterizedType.typeArguments().add(ast.newSimpleType(ast.newName(String.class.getTypeName())));
    parameterizedType.typeArguments().add(new TypeInfo(VMHelpConfig.class).getType(ast, entityGenContext));
    variableDeclarationStatement.setType(parameterizedType);
    block.statements().add(variableDeclarationStatement);
  }

  private void addPutItemsStatements(Block block) {
    GspViewModel model = (GspViewModel) entityGenContext.getCommonModel();

    java.util.HashMap<String, VMHelpConfig> dic = new java.util.HashMap<String, VMHelpConfig>();

    ValueHelpConfigCollection helpInfos = model.getValueHelpConfigs();
    for (ValueHelpConfig config:helpInfos)
    {
      String originalKey = config.getElementId(); //此ID分两段，用/区分
      String[] info = originalKey.split("[/]", -1);
      if (info.length != 2) {
        throw new RuntimeException("ValueHelpConfig对象的ElementId字段不符合约定");
      }
      String key = info[0] + info[1];

      java.util.ArrayList<ReflectInfo> list = new java.util.ArrayList<ReflectInfo>();
      if (config.getHelpExtend() != null && config.getHelpExtend().getBeforeHelp() != null) {


        for (ViewModelAction helpAction : config.getHelpExtend().getBeforeHelp()) {
          MappedCdpAction action = (MappedCdpAction) helpAction;
          GspMetadata metadata = vmGenContext.getMetadataPool()
                  .getMetadata(action.getComponentPkgName(), action.getComponentEntityId());

          VMComponent compMetadata = (VMComponent) ((metadata.getContent() instanceof VMComponent)
                  ? metadata.getContent() : null);
          if (compMetadata == null) {
            throw new RuntimeException("加载构件失败");
          }
          List<ParameterInfo> parameters = new ArrayList<>();
          for(int i=0;i<action.getParameterCollection().getCount();i++)
          {
            //todo 是不是有问题呢？
            ViewModelParameter parameter = (ViewModelParameter)action.getParameterCollection().getItem(i);
            String parameterValue =parameter.getActualValue().getValue() == null ? "" :parameter.getActualValue().getValue();
            ParameterInfo parameterInfo = new ParameterInfo(parameter.getParamCode(), parameterValue);
            parameters.add(parameterInfo);
          }
          VMMethod method = compMetadata.getVmMethod();
          String assemblyName = method.getAssembly();
          String className = method.getClassName();
          list.add(new ReflectInfo(assemblyName, className, parameters));
        }
      }

      VMHelpConfig tempVar = new VMHelpConfig();
      tempVar.setHelpId(config.getHelperId());
      tempVar.setActionRecord(list);
      tempVar.setUseCustomAuthInfo(config.getEnableCustomHelpAuth());
      tempVar.setVoID(model.getID());
      tempVar.setHelpElementID(config.getElementId());
      dic.put(key, tempVar);
    }

    for(Map.Entry<String,VMHelpConfig> entry:dic.entrySet())
    {
      addPutItemStatement(block,entry);
    }
  }

  private void addPutItemStatement(Block block, Map.Entry<String, VMHelpConfig> entry) {
//    Block block1=ast.newBlock();
    String keyValue = entry.getKey();
    String key = keyValue.replaceAll("_","").replaceAll("-","");
    String valName = "val"+key;
    String listValName = "val"+key +"List";
    addNewVMHelpConfig(block,entry,valName);
    addSetHelpId(block,entry, valName);
    addNewReflectInfos(block,entry,listValName);
    addSetReflectInfoItems(block,entry, listValName);
    addSetActionRecord(block,entry,valName, listValName);
    addSetUseCustomAuth(block,entry,valName,listValName);
    addSetVoID(block,entry,valName,listValName);
    addSetHelpElementID(block,entry,valName,listValName);
    addPutMapItem(block,entry,valName);
//    block.statements().add(block1);
  }

  private void addSetVoID(Block block, Map.Entry<String, VMHelpConfig> entry, String valName, String listValName) {
    MethodInvocation methodInvocation=ast.newMethodInvocation();
    methodInvocation.setName(ast.newSimpleName("setVoID"));
    methodInvocation.setExpression(ast.newSimpleName(valName));
    StringLiteral stringLiteral=ast.newStringLiteral();
    stringLiteral.setLiteralValue(entry.getValue().getVoID());
    methodInvocation.arguments().add(stringLiteral);

    block.statements().add(ast.newExpressionStatement(methodInvocation));
  }

  private void addSetHelpElementID(Block block, Map.Entry<String, VMHelpConfig> entry, String valName, String listValName) {
    MethodInvocation methodInvocation=ast.newMethodInvocation();
    methodInvocation.setName(ast.newSimpleName("setHelpElementID"));
    methodInvocation.setExpression(ast.newSimpleName(valName));
    StringLiteral stringLiteral=ast.newStringLiteral();
    stringLiteral.setLiteralValue(entry.getValue().getHelpElementID());
    methodInvocation.arguments().add(stringLiteral);

    block.statements().add(ast.newExpressionStatement(methodInvocation));
  }

  private void addSetUseCustomAuth(Block block, Map.Entry<String, VMHelpConfig> entry, String valName, String listValName) {
    MethodInvocation methodInvocation=ast.newMethodInvocation();
    methodInvocation.setName(ast.newSimpleName("setUseCustomAuthInfo"));
    methodInvocation.setExpression(ast.newSimpleName(valName));
    methodInvocation.arguments().add(ast.newBooleanLiteral(entry.getValue().getUseCustomAuthInfo()));

    block.statements().add(ast.newExpressionStatement(methodInvocation));
  }

  //  VMHelpConfig val = new VMHelpConfig();
  private void addNewVMHelpConfig(Block block1, Map.Entry<String, VMHelpConfig> entry,String valName) {
    VariableDeclarationFragment variableDeclarationFragment=ast.newVariableDeclarationFragment();
    variableDeclarationFragment.setName(ast.newSimpleName(valName));
    ClassInstanceCreation classInstanceCreation=ast.newClassInstanceCreation();
    Type helpConfigType = new TypeInfo(VMHelpConfig.class).getType(ast, entityGenContext);
    classInstanceCreation.setType(helpConfigType);
    variableDeclarationFragment.setInitializer(classInstanceCreation);

    VariableDeclarationStatement variableDeclarationStatement=ast.newVariableDeclarationStatement(variableDeclarationFragment);
    Type helpConfigType1 = new TypeInfo(VMHelpConfig.class).getType(ast, entityGenContext);
    variableDeclarationStatement.setType(helpConfigType1);
    block1.statements().add(variableDeclarationStatement);
  }

//   val.setHelpId("aaa");
  private void addSetHelpId(Block block1, Map.Entry<String, VMHelpConfig> entry,String valName)
  {
    MethodInvocation methodInvocation=ast.newMethodInvocation();
    methodInvocation.setExpression(ast.newSimpleName(valName));
    methodInvocation.setName(ast.newSimpleName("setHelpId"));
    StringLiteral stringLiteral=ast.newStringLiteral();
    stringLiteral.setLiteralValue(entry.getValue().getHelpId());
    methodInvocation.arguments().add(stringLiteral);

    block1.statements().add(ast.newExpressionStatement(methodInvocation));
  }

//  ArrayList<ReflectInfo> list = new ArrayList<>();
  private void addNewReflectInfos(Block block, Map.Entry<String, VMHelpConfig> entry,String listValName)
  {
    VariableDeclarationFragment variableDeclarationFragment=ast.newVariableDeclarationFragment();
    variableDeclarationFragment.setName(ast.newSimpleName(listValName));
    ClassInstanceCreation classInstanceCreation=ast.newClassInstanceCreation();

    Type listType = new TypeInfo(ArrayList.class).getType(ast, entityGenContext);
    Type reflectType = new TypeInfo(ReflectInfo.class).getType(ast, entityGenContext);
    ParameterizedType parameterizedType1=ast.newParameterizedType(listType);
    parameterizedType1.typeArguments().add(reflectType);
    classInstanceCreation.setType(parameterizedType1);
    variableDeclarationFragment.setInitializer(classInstanceCreation);

    Type listType2 = new TypeInfo(ArrayList.class).getType(ast, entityGenContext);
    Type reflectType2 = new TypeInfo(ReflectInfo.class).getType(ast, entityGenContext);
    VariableDeclarationStatement variableDeclarationStatement=ast.newVariableDeclarationStatement(variableDeclarationFragment);
    ParameterizedType parameterizedType=ast.newParameterizedType(listType2);
    parameterizedType.typeArguments().add(reflectType2);
    variableDeclarationStatement.setType(parameterizedType);
    block.statements().add(variableDeclarationStatement);
  }

  // list.add(new ReflectInfo("",""));
  private void addSetReflectInfoItems(Block block, Map.Entry<String, VMHelpConfig> entry,String listValName)
  {
    if(entry.getValue().getActionRecord()==null||entry.getValue().getActionRecord().size()==0)
      return;
    int index = 1;
    for (ReflectInfo reflectInfo:entry.getValue().getActionRecord())
    {
      //含有参数
      String varListName = listValName + index++;
      if(!reflectInfo.getParameterInfoList().isEmpty()){
        addParameterInfo(block, reflectInfo, varListName);
      }
      MethodInvocation methodInvocation=ast.newMethodInvocation();
      methodInvocation.setName(ast.newSimpleName("add"));
      methodInvocation.setExpression(ast.newSimpleName(listValName));

      ClassInstanceCreation classInstanceCreation=ast.newClassInstanceCreation();
      classInstanceCreation.setType(new TypeInfo(ReflectInfo.class).getType(ast, entityGenContext));
      StringLiteral stringLiteral1=ast.newStringLiteral();
      stringLiteral1.setLiteralValue(reflectInfo.getAssemblyName());
      classInstanceCreation.arguments().add(stringLiteral1);
      StringLiteral stringLiteral2=ast.newStringLiteral();
      stringLiteral2.setLiteralValue(reflectInfo.getClassName());
      classInstanceCreation.arguments().add(stringLiteral2);
      if(!reflectInfo.getParameterInfoList().isEmpty()){
        classInstanceCreation.arguments().add(ast.newSimpleName(varListName));
      }
      methodInvocation.arguments().add(classInstanceCreation);

      block.statements().add(ast.newExpressionStatement(methodInvocation));
    }
  }

  //生成添加参数代码
  private void addParameterInfo(Block block, ReflectInfo reflectInfo, String varListName)
  {
    VariableDeclarationFragment variableDeclarationFragment = ast.newVariableDeclarationFragment();
    ClassInstanceCreation classInstanceCreation = ast.newClassInstanceCreation();
    ParameterizedType parameterizedType = ast.newParameterizedType(ast.newSimpleType(ast.newSimpleName("ArrayList")));
    parameterizedType.typeArguments().add(ast.newSimpleType(ast.newSimpleName("ParameterInfo")));
    classInstanceCreation.setType(parameterizedType);

    variableDeclarationFragment.setName(ast.newSimpleName(varListName));
    variableDeclarationFragment.setInitializer(classInstanceCreation);

    VariableDeclarationStatement variableDeclarationStatement = ast.newVariableDeclarationStatement(variableDeclarationFragment);
    ParameterizedType parameterizedType1 = ast.newParameterizedType(ast.newSimpleType(ast.newSimpleName("ArrayList")));
    parameterizedType1.typeArguments().add(ast.newSimpleType(ast.newSimpleName("ParameterInfo")));
    variableDeclarationStatement.setType(parameterizedType1);

    block.statements().add(variableDeclarationStatement);
    for(ParameterInfo parameterInfo:reflectInfo.getParameterInfoList()){
      MethodInvocation methodInvocation = ast.newMethodInvocation();
      methodInvocation.setExpression(ast.newSimpleName(varListName));
      methodInvocation.setName(ast.newSimpleName("add"));
      ClassInstanceCreation classInstanceCreation1 = ast.newClassInstanceCreation();
      classInstanceCreation1.setType(ast.newSimpleType(ast.newSimpleName("ParameterInfo")));
      StringLiteral stringLiteral1=ast.newStringLiteral();
      stringLiteral1.setLiteralValue(parameterInfo.getParameterName());
      classInstanceCreation1.arguments().add(stringLiteral1);
      StringLiteral stringLiteral2=ast.newStringLiteral();
      stringLiteral2.setLiteralValue(parameterInfo.getParameterValue());
      classInstanceCreation1.arguments().add(stringLiteral2);
      methodInvocation.arguments().add(classInstanceCreation1);
      block.statements().add(ast.newExpressionStatement(methodInvocation));
    }
  }

//   val.setActionRecord(list);
  private void addSetActionRecord(Block block, Map.Entry<String, VMHelpConfig> entry, String valName, String valListName)
  {
    MethodInvocation methodInvocation=ast.newMethodInvocation();
    methodInvocation.setName(ast.newSimpleName("setActionRecord"));
    methodInvocation.setExpression(ast.newSimpleName(valName));
    methodInvocation.arguments().add(ast.newSimpleName(valListName));

    block.statements().add(ast.newExpressionStatement(methodInvocation));
  }

//    map.put("123",val);
  private void addPutMapItem(Block block, Map.Entry<String, VMHelpConfig> entry, String valName)
  {
      MethodInvocation methodInvocation=ast.newMethodInvocation();
      methodInvocation.setExpression(ast.newSimpleName("map"));
      methodInvocation.setName(ast.newSimpleName("put"));
      StringLiteral stringLiteral=ast.newStringLiteral();
      stringLiteral.setLiteralValue(entry.getKey());
      methodInvocation.arguments().add(stringLiteral);
      methodInvocation.arguments().add(ast.newSimpleName(valName));

      block.statements().add(ast.newExpressionStatement(methodInvocation));
  }
// return map;
  private void addReturnStatement(Block block)
  {
    ReturnStatement returnStatement=ast.newReturnStatement();
    returnStatement.setExpression(ast.newSimpleName("map"));
    block.statements().add(returnStatement);
  }


//  private void Test()
//  {
//    HashMap<String,VMHelpConfig> map=new HashMap<>();
//    {
//      VMHelpConfig val = new VMHelpConfig();
//      val.setHelpId("aaa");
//      ArrayList<ReflectInfo> list = new ArrayList<>();
//      list.add(new ReflectInfo("",""));
//      val.setActionRecord(list);
//      map.put("123",val);
//
//    }
//    return map;
//    {
//      VMHelpConfig val=new VMHelpConfig();
//    }
//  }

  @Override
  protected boolean hasSetMethod() {
    return false;
  }
}
